package com.lt.system;

import android.annotation.SuppressLint;

import com.lt.common.ConvertHelper;
import com.lt.LibConstant;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;

public class DateTimeHelper
{

    private static DateTimeHelper instance;
    public static final String simpleTime = "yyyy-MM-dd HH:mm:ss";
    public static final String simpleTimeM = "yyyy-MM-dd HH:mm";
    public static final String simpleDate = "yyyy-MM-dd";
    public static final String fmtHms = "HH:mm:ss";

    private DateTimeHelper()
    {
    }

    public static DateTimeHelper getInstance()
    {
        if (instance == null)
        {
            synchronized (DateTimeHelper.class)
            {
                instance = new DateTimeHelper();
            }
        }
        return instance;
    }

    /**
     * <p>
     * 在工具类中经常使用到工具类的格式化描述，这个主要是一个日期的操作类，所以日志格式主要使用 SimpleDateFormat的定义格式.
     * </p>
     * 格式的意义如下： 日期和时间模式 <br>
     * <p>
     * 日期和时间格式由日期和时间模式字符串指定。在日期和时间模式字符串中，未加引号的字母 'A' 到 'Z' 和 'a' 到 'z'
     * 被解释为模式字母，用来表示日期或时间字符串元素。文本可以使用单引号 (') 引起来，以免进行解释。"''"
     * 表示单引号。所有其他字符均不解释；只是在格式化时将它们简单复制到输出字符串，或者在分析时与输入字符串进行匹配。
     * </p>
     * 定义了以下模式字母（所有其他字符 'A' 到 'Z' 和 'a' 到 'z' 都被保留）： <br>
     * <table border="1" cellspacing="1" cellpadding="1" summary="Chart shows pattern letters, date/time component, * presentation, and examples.">
     * <tr>
     * <th align="left">字母</th>
     * <th align="left">日期或时间元素</th>
     * <th align="left">表示</th>
     * <th align="left">示例</th>
     * </tr>
     * <tr>
     * <td><code>G</code></td>
     * <td>Era 标志符</td>
     * <td>Text</td>
     * <td><code>AD</code></td>
     * </tr>
     * <tr>
     * <td><code>y</code></td>
     * <td>年</td>
     * <td>Year</td>
     * <td><code>1996</code>; <code>96</code></td>
     * </tr>
     * <tr>
     * <td><code>M</code></td>
     * <td>年中的月份</td>
     * <td>Month</td>
     * <td><code>July</code>; <code>Jul</code>; <code>07</code></td>
     * </tr>
     * <tr>
     * <td><code>w</code></td>
     * <td>年中的周数</td>
     * <td>Number</td>
     * <td><code>27</code></td>
     * </tr>
     * <tr>
     * <td><code>W</code></td>
     * <td>月份中的周数</td>
     * <td>Number</td>
     * <td><code>2</code></td>
     * </tr>
     * <tr>
     * <td><code>D</code></td>
     * <td>年中的天数</td>
     * <td>Number</td>
     * <td><code>189</code></td>
     * </tr>
     * <tr>
     * <td><code>d</code></td>
     * <td>月份中的天数</td>
     * <td>Number</td>
     * <td><code>10</code></td>
     * </tr>
     * <tr>
     * <td><code>F</code></td>
     * <td>月份中的星期</td>
     * <td>Number</td>
     * <td><code>2</code></td>
     * </tr>
     * <tr>
     * <td><code>E</code></td>
     * <td>星期中的天数</td>
     * <td>Text</td>
     * <td><code>Tuesday</code>; <code>Tue</code></td>
     * </tr>
     * <tr>
     * <td><code>a</code></td>
     * <td>Am/pm 标记</td>
     * <td>Text</td>
     * <td><code>PM</code></td>
     * </tr>
     * <tr>
     * <td><code>H</code></td>
     * <td>一天中的小时数（0-23）</td>
     * <td>Number</td>
     * <td><code>0</code></td>
     * </tr>
     * <tr>
     * <td><code>k</code></td>
     * <td>一天中的小时数（1-24）</td>
     * <td>Number</td>
     * <td><code>24</code></td>
     * </tr>
     * <tr>
     * <td><code>K</code></td>
     * <td>am/pm 中的小时数（0-11）</td>
     * <td>Number</td>
     * <td><code>0</code></td>
     * </tr>
     * <tr>
     * <td><code>h</code></td>
     * <td>am/pm 中的小时数（1-12）</td>
     * <td>Number</td>
     * <td><code>12</code></td>
     * </tr>
     * <tr>
     * <td><code>m</code></td>
     * <td>小时中的分钟数</td>
     * <td>Number</td>
     * <td><code>30</code></td>
     * </tr>
     * <tr>
     * <td><code>s</code></td>
     * <td>分钟中的秒数</td>
     * <td>Number</td>
     * <td><code>55</code></td>
     * </tr>
     * <tr>
     * <td><code>S</code></td>
     * <td>毫秒数</td>
     * <td>Number</td>
     * <td><code>978</code></td>
     * </tr>
     * <tr>
     * <td><code>z</code></td>
     * <td>时区</td>
     * <td>General time zone</td>
     * <td><code>Pacific Standard Time</code>; <code>PST</code>;
     * <code>GMT-08:00</code></td>
     * </tr>
     * <tr>
     * <td><code>Z</code></td>
     * <td>时区</td>
     * <td>RFC 822 time zone</td>
     * <td><code>-0800</code></td>
     * </tr>
     * </table>
     * <p>
     * <pre>
     *                          HH:mm    15:44
     *                         h:mm a    3:44 下午
     *                        HH:mm z    15:44 CST
     *                        HH:mm Z    15:44 +0800
     *                     HH:mm zzzz    15:44 中国标准时间
     *                       HH:mm:ss    15:44:40
     *                     yyyy-MM-dd    2016-08-12
     *               yyyy-MM-dd HH:mm    2016-08-12 15:44
     *            yyyy-MM-dd HH:mm:ss    2016-08-12 15:44:40
     *       yyyy-MM-dd HH:mm:ss zzzz    2016-08-12 15:44:40 中国标准时间
     *  EEEE yyyy-MM-dd HH:mm:ss zzzz    星期五 2016-08-12 15:44:40 中国标准时间
     *       yyyy-MM-dd HH:mm:ss.SSSZ    2016-08-12 15:44:40.461+0800
     *     yyyy-MM-dd'T'HH:mm:ss.SSSZ    2016-08-12T15:44:40.461+0800
     *   yyyy.MM.dd G 'at' HH:mm:ss z    2016.08.12 公元 at 15:44:40 CST
     *                         K:mm a    3:44 下午
     *               EEE, MMM d, ''yy    星期五, 八月 12, '16
     *          hh 'o''clock' a, zzzz    03 o'clock 下午, 中国标准时间
     *   yyyyy.MMMMM.dd GGG hh:mm aaa    02016.八月.12 公元 03:44 下午
     *     EEE, d MMM yyyy HH:mm:ss Z    星期五, 12 八月 2016 15:44:40 +0800
     *                  yyMMddHHmmssZ    160812154440+0800
     *     yyyy-MM-dd'T'HH:mm:ss.SSSZ    2016-08-12T15:44:40.461+0800
     * EEEE 'DATE('yyyy-MM-dd')' 'TIME('HH:mm:ss')' zzzz    星期五 DATE(2016-08-12) TIME(15:44:40) 中国标准时间
     * </pre>
     * <p>
     * 注意：SimpleDateFormat不是线程安全的，线程安全需用{@code ThreadLocal<SimpleDateFormat>}
     */


    /**
     * 将时间戳转为时间字符串
     *
     * @param pattern 时间的样式-- yyyy年MM月dd日HH小时mm分钟ss秒
     * @param time    时间戳---（0表示格式化当前时间）
     * @return
     */
    public String formatSimpleTime(long time, String pattern)
    {
        return formatSimpleTime((time == 0) ? new Date()
                : new Date(time), pattern);
    }

    public String formatSimpleTime(long time)
    {
        return formatSimpleTime(time, simpleTime);
    }

    public String formatSimpleTime(Date date)
    {
        return formatSimpleTime(date, simpleTime);
    }

    public String formatSimpleTime()
    {
        return formatSimpleTime(new Date(), simpleTime);
    }

    public String formatSimpleTime(Date date, String format)
    {
        return date == null ? null : new SimpleDateFormat(format,
                Locale.getDefault()).format(date);
    }

    public String formatSimpleDate(Date date)
    {
        return formatSimpleTime(date, simpleDate);
    }

    public String formatSimpleDate()
    {
        return formatSimpleDate(new Date());
    }

    /**
     * 将字符串格式时间转换成Date
     *
     * @param pattern 字符串时间的格式，如：2014-10-10 10:10:10，format：yyyy-MM-dd HH:mm:ss
     */
    public Date str2Date(String time, String pattern)
    {
        SimpleDateFormat sDateFormat = new SimpleDateFormat(pattern,
                Locale.getDefault());
        Date date = null;
        try
        {
            date = sDateFormat.parse(time);
        } catch (ParseException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return null;
        }
        return date;
    }

    /**
     * 将时间字符串转为时间戳
     *
     * @param time    时间字符串
     * @param pattern 时间格式
     * @return 毫秒时间戳
     */
    public long str2Millis(String time, String pattern)
    {
        Date date = str2Date(time, pattern);
        return (date == null) ? -1 : date.getTime();
    }

    public long getStartOfDayInMillis()
    {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTimeInMillis();
    }

    public long getEndOfDayInMillis()
    {
        // Add one day's time to the beginning of the day.
        // 24 hours * 60 minutes * 60 seconds * 1000 milliseconds = 1 day
        return getStartOfDayInMillis() + (24 * 60 * 60 * 1000);
    }

    /**
     * @param date the date in the format "yyyy-MM-dd"
     */
    public long getStartOfDayInMillis(String date) throws ParseException
    {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(format.parse(date));
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTimeInMillis();
    }

    /**
     * @param date the date in the format "yyyy-MM-dd"
     */
    public long getEndOfDayInMillis(String date) throws ParseException
    {
        // Add one day's time to the beginning of the day.
        // 24 hours * 60 minutes * 60 seconds * 1000 milliseconds = 1 day
        return getStartOfDayInMillis(date) + (24 * 60 * 60 * 1000);
    }

    /**
     * 获取两个时间差（单位：unit）
     * <p>
     * time0和time1格式都为format
     * </p>
     *
     * @param time0   时间字符串0
     * @param time1   时间字符串1
     * @param unit    单位类型
     *                <ul>
     *                <li>{@link LibConstant.TimeUnit#MSEC}: 毫秒</li>
     *                <li>{@link LibConstant.TimeUnit#SEC }: 秒</li>
     *                <li>{@link LibConstant.TimeUnit#MIN }: 分</li>
     *                <li>{@link LibConstant.TimeUnit#HOUR}: 小时</li>
     *                <li>{@link LibConstant.TimeUnit#DAY }: 天</li>
     *                </ul>
     * @param pattern 时间格式
     * @return unit时间戳
     */
    public long getTimeSpan(String time0, String time1,
                            LibConstant.TimeUnit unit, String pattern)
    {
        return ConvertHelper.getInstance().millis2TimeSpan(
                Math.abs(str2Millis(time0, pattern)
                        - str2Millis(time1, pattern)), unit);
    }

    /**
     * 获取两个时间差（单位：unit）
     *
     * @param date0 Date类型时间0
     * @param date1 Date类型时间1
     * @param unit  单位类型
     *              <ul>
     *              <li>{@link LibConstant.TimeUnit#MSEC}: 毫秒</li>
     *              <li>{@link LibConstant.TimeUnit#SEC }: 秒</li>
     *              <li>{@link LibConstant.TimeUnit#MIN }: 分</li>
     *              <li>{@link LibConstant.TimeUnit#HOUR}: 小时</li>
     *              <li>{@link LibConstant.TimeUnit#DAY }: 天</li>
     *              </ul>
     * @return unit时间戳
     */
    public long getTimeSpan(Date date0, Date date1,
                            LibConstant.TimeUnit unit)
    {
        return ConvertHelper.getInstance().millis2TimeSpan(
                Math.abs(date0.getTime() - date1.getTime()), unit);
    }

    /**
     * 获取两个时间差（单位：unit）
     *
     * @param millis0 毫秒时间戳0
     * @param millis1 毫秒时间戳1
     * @param unit    单位类型
     *                <ul>
     *                <li>{@link LibConstant.TimeUnit#MSEC}: 毫秒</li>
     *                <li>{@link LibConstant.TimeUnit#SEC }: 秒</li>
     *                <li>{@link LibConstant.TimeUnit#MIN }: 分</li>
     *                <li>{@link LibConstant.TimeUnit#HOUR}: 小时</li>
     *                <li>{@link LibConstant.TimeUnit#DAY }: 天</li>
     *                </ul>
     * @return unit时间戳
     */
    public long getTimeSpan(long millis0, long millis1,
                            LibConstant.TimeUnit unit)
    {
        return ConvertHelper.getInstance().millis2TimeSpan(Math.abs(millis0 - millis1), unit);
    }

    /**
     * 获取合适型两个时间差
     * <p>
     * time0和time1格式都为pattern
     * </p>
     *
     * @param time0     时间字符串0
     * @param time1     时间字符串1
     * @param precision 精度
     *                  <p>
     *                  precision = 0，返回null
     *                  </p>
     *                  <p>
     *                  precision = 1，返回天
     *                  </p>
     *                  <p>
     *                  precision = 2，返回天和小时
     *                  </p>
     *                  <p>
     *                  precision = 3，返回天、小时和分钟
     *                  </p>
     *                  <p>
     *                  precision = 4，返回天、小时、分钟和秒
     *                  </p>
     *                  <p>
     *                  precision >= 5，返回天、小时、分钟、秒和毫秒
     *                  </p>
     * @param pattern   时间格式
     * @return 合适型两个时间差
     */
    public String getFitTimeSpan(String time0, String time1,
                                 int precision, String pattern)
    {
        return ConvertHelper.getInstance().millis2FitTimeSpan(
                Math.abs(str2Millis(time0, pattern)
                        - str2Millis(time1, pattern)), precision);
    }

    /**
     * 获取星期
     * <p>
     * time格式为pattern
     * </p>
     *
     * @param time    时间字符串
     * @param pattern 时间格式
     * @return 星期
     */
    public String getWeek(String time, String pattern)
    {
        return getWeek(str2Date(time, pattern));
    }

    /**
     * 获取星期
     *
     * @param date Date类型时间
     * @return 星期
     */
    public String getWeek(Date date)
    {
        return new SimpleDateFormat("EEEE", Locale.getDefault()).format(date);
    }

    /**
     * 获取星期
     *
     * @param millis 毫秒时间戳
     * @return 星期
     */
    public String getWeek(long millis)
    {
        return getWeek(new Date(millis));
    }

    /**
     * 获取星期
     * <p>
     * 注意：周日的Index才是1，周六为7
     * </p>
     * <p>
     * time格式为pattern
     * </p>
     *
     * @param time    时间字符串
     * @param pattern 时间格式
     * @return 1...7
     */
    public int getWeekIndex(String time, String pattern)
    {
        return getWeekIndex(str2Date(time, pattern));
    }

    /**
     * 获取星期
     * <p>
     * 注意：周日的Index才是1，周六为7
     * </p>
     *
     * @param date Date类型时间
     * @return 1...7
     */
    public int getWeekIndex(Date date)
    {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.get(Calendar.DAY_OF_WEEK);
    }

    /**
     * 获取星期
     * <p>
     * 注意：周日的Index才是1，周六为7
     * </p>
     *
     * @param millis 毫秒时间戳
     * @return 1...7
     */
    public int getWeekIndex(long millis)
    {
        return getWeekIndex(new Date(millis));
    }

    /**
     * 获取月份中的第几周
     * <p>
     * 注意：国外周日才是新的一周的开始
     * </p>
     * <p>
     * time格式为pattern
     * </p>
     *
     * @param time    时间字符串
     * @param pattern 时间格式
     * @return 1...5
     */
    public int getWeekOfMonth(String time, String pattern)
    {
        return getWeekOfMonth(str2Date(time, pattern));
    }

    /**
     * 获取月份中的第几周
     * <p>
     * 注意：国外周日才是新的一周的开始
     * </p>
     *
     * @param date Date类型时间
     * @return 1...5
     */
    public int getWeekOfMonth(Date date)
    {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.get(Calendar.WEEK_OF_MONTH);
    }

    /**
     * 获取月份中的第几周
     * <p>
     * 注意：国外周日才是新的一周的开始
     * </p>
     *
     * @param millis 毫秒时间戳
     * @return 1...5
     */
    public int getWeekOfMonth(long millis)
    {
        return getWeekOfMonth(new Date(millis));
    }

    /**
     * 获取年份中的第几周
     * <p>
     * 注意：国外周日才是新的一周的开始
     * </p>
     * <p>
     * time格式为pattern
     * </p>
     *
     * @param time    时间字符串
     * @param pattern 时间格式
     * @return 1...54
     */
    public int getWeekOfYear(String time, String pattern)
    {
        return getWeekOfYear(str2Date(time, pattern));
    }

    /**
     * 获取年份中的第几周
     * <p>
     * 注意：国外周日才是新的一周的开始
     * </p>
     *
     * @param date Date类型时间
     * @return 1...54
     */
    public int getWeekOfYear(Date date)
    {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.get(Calendar.WEEK_OF_YEAR);
    }

    /**
     * 获取年份中的第几周
     * <p>
     * 注意：国外周日才是新的一周的开始
     * </p>
     *
     * @param millis 毫秒时间戳
     * @return 1...54
     */
    public int getWeekOfYear(long millis)
    {
        return getWeekOfYear(new Date(millis));
    }

    private static final String[] CHINESE_ZODIAC = {"猴", "鸡", "狗", "猪", "鼠",
            "牛", "虎", "兔", "龙", "蛇", "马", "羊"};

    /**
     * 获取生肖
     * <p>
     * time格式为pattern
     * </p>
     *
     * @param time    时间字符串
     * @param pattern 时间格式
     * @return 生肖
     */
    public String getChineseZodiac(String time, String pattern)
    {
        return getChineseZodiac(str2Date(time, pattern));
    }

    /**
     * 获取生肖
     *
     * @param date Date类型时间
     * @return 生肖
     */
    public String getChineseZodiac(Date date)
    {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return CHINESE_ZODIAC[cal.get(Calendar.YEAR) % 12];
    }

    /**
     * 获取生肖
     *
     * @param millis 毫秒时间戳
     * @return 生肖
     */
    public String getChineseZodiac(long millis)
    {
        return getChineseZodiac(new Date(millis));
    }

    /**
     * 获取生肖
     *
     * @param year 年
     * @return 生肖
     */
    public String getChineseZodiac(int year)
    {
        return CHINESE_ZODIAC[year % 12];
    }

    /**
     * 判断是否闰年
     * <p>
     * time格式为pattern
     * </p>
     *
     * @param time    时间字符串
     * @param pattern 时间格式
     * @return {@code true}: 闰年<br>
     * {@code false}: 平年
     */
    public boolean isLeapYear(String time, String pattern)
    {
        return isLeapYear(str2Date(time, pattern));
    }

    /**
     * 判断是否闰年
     *
     * @param date Date类型时间
     * @return {@code true}: 闰年<br>
     * {@code false}: 平年
     */
    public boolean isLeapYear(Date date)
    {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int year = cal.get(Calendar.YEAR);
        return isLeapYear(year);
    }

    /**
     * 判断是否闰年
     *
     * @param millis 毫秒时间戳
     * @return {@code true}: 闰年<br>
     * {@code false}: 平年
     */
    public boolean isLeapYear(long millis)
    {
        return isLeapYear(new Date(millis));
    }

    /**
     * 判断是否闰年
     *
     * @param year 年份
     * @return {@code true}: 闰年<br>
     * {@code false}: 平年
     */
    public boolean isLeapYear(int year)
    {
        return year % 4 == 0 && year % 100 != 0 || year % 400 == 0;
    }

    /**
     * 判断是否同一天
     * <p>
     * time格式为pattern
     * </p>
     *
     * @param time    时间字符串
     * @param pattern 时间格式
     * @return {@code true}: 是<br>
     * {@code false}: 否
     */
    public boolean isSameDay(String time, String pattern)
    {
        return isSameDay(str2Millis(time, pattern));
    }

    /**
     * 判断是否同一天
     *
     * @param date Date类型时间
     * @return {@code true}: 是<br>
     * {@code false}: 否
     */
    public boolean isSameDay(Date date)
    {
        return isSameDay(date.getTime());
    }

    /**
     * 判断是否同一天
     *
     * @param millis 毫秒时间戳
     * @return {@code true}: 是<br>
     * {@code false}: 否
     */
    public boolean isSameDay(long millis)
    {
        long wee = (System.currentTimeMillis() / LibConstant.DAY)
                * LibConstant.DAY;
        return millis >= wee && millis < wee + LibConstant.DAY;
    }

    /**
     * 获取友好型与当前时间的差
     *
     * @param millis 毫秒时间戳
     * @return 友好型与当前时间的差
     * <ul>
     * <li>如果小于1秒钟内，显示刚刚</li>
     * <li>如果在1分钟内，显示XXX秒前</li>
     * <li>如果在1小时内，显示XXX分钟前</li>
     * <li>如果在1小时外的今天内，显示今天15:32</li>
     * <li>如果是昨天的，显示昨天15:32</li>
     * <li>其余显示，2016-10-15</li>
     * <li>时间不合法的情况全部日期和时间信息，如星期六 十月 27 14:21:20 CST 2007</li>
     * </ul>
     */
    @SuppressLint("DefaultLocale")
    public String getFriendlyTimeSpanByNow(long millis)
    {
        long now = System.currentTimeMillis();
        long span = now - millis;
        if (span < 0)
            return String.format("%tc", millis);// U can read
        // http://www.apihome.cn/api/java/Formatter.html
        // to understand it.
        if (span < 1000)
        {
            return "刚刚";
        } else if (span < LibConstant.MIN)
        {
            return String.format("%d秒前", span / LibConstant.SEC);
        } else if (span < LibConstant.HOUR)
        {
            return String.format("%d分钟前", span / LibConstant.MIN);
        }
        // 获取当天00:00
        long wee = (now / LibConstant.DAY) * LibConstant.DAY;
        if (millis >= wee)
        {
            return String.format("今天%tR", millis);
        } else if (millis >= wee - LibConstant.DAY)
        {
            return String.format("昨天%tR", millis);
        } else
        {
            return String.format("%tF", millis);
        }
    }

    /**
     * 获取友好型与当前时间的差
     * <p>
     * time格式为pattern
     * </p>
     *
     * @param time    时间字符串
     * @param pattern 时间格式
     * @return 友好型与当前时间的差
     * <ul>
     * <li>如果小于1秒钟内，显示刚刚</li>
     * <li>如果在1分钟内，显示XXX秒前</li>
     * <li>如果在1小时内，显示XXX分钟前</li>
     * <li>如果在1小时外的今天内，显示今天15:32</li>
     * <li>如果是昨天的，显示昨天15:32</li>
     * <li>其余显示，2016-10-15</li>
     * <li>时间不合法的情况全部日期和时间信息，如星期六 十月 27 14:21:20 CST 2007</li>
     * </ul>
     */
    public String getFriendlyTimeSpanByNow(String time, String pattern)
    {
        return getFriendlyTimeSpanByNow(str2Millis(time, pattern));
    }

    /**
     * 获取友好型与当前时间的差
     *
     * @param date Date类型时间
     * @return 友好型与当前时间的差
     * <ul>
     * <li>如果小于1秒钟内，显示刚刚</li>
     * <li>如果在1分钟内，显示XXX秒前</li>
     * <li>如果在1小时内，显示XXX分钟前</li>
     * <li>如果在1小时外的今天内，显示今天15:32</li>
     * <li>如果是昨天的，显示昨天15:32</li>
     * <li>其余显示，2016-10-15</li>
     * <li>时间不合法的情况全部日期和时间信息，如星期六 十月 27 14:21:20 CST 2007</li>
     * </ul>
     */
    public String getFriendlyTimeSpanByNow(Date date)
    {
        return getFriendlyTimeSpanByNow(date.getTime());
    }

    private static final String[] ZODIAC = {"水瓶座", "双鱼座", "白羊座", "金牛座", "双子座",
            "巨蟹座", "狮子座", "处女座", "天秤座", "天蝎座", "射手座", "魔羯座"};
    private static final int[] ZODIAC_FLAGS = {20, 19, 21, 21, 21, 22, 23, 23,
            23, 24, 23, 22};

    /**
     * 获取星座
     * <p>
     * time格式为pattern
     * </p>
     *
     * @param time    时间字符串
     * @param pattern 时间格式
     * @return 生肖
     */
    public String getZodiac(String time, String pattern)
    {
        return getZodiac(str2Date(time, pattern));
    }

    /**
     * 获取星座
     *
     * @param date Date类型时间
     * @return 星座
     */
    public String getZodiac(Date date)
    {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int month = cal.get(Calendar.MONTH) + 1;
        int day = cal.get(Calendar.DAY_OF_MONTH);
        return getZodiac(month, day);
    }

    /**
     * 获取星座
     *
     * @param millis 毫秒时间戳
     * @return 星座
     */
    public String getZodiac(long millis)
    {
        return getZodiac(new Date(millis));
    }

    /**
     * 获取星座
     *
     * @return 星座
     */
    public String getZodiac(int month, int day)
    {
        return ZODIAC[day >= ZODIAC_FLAGS[month - 1] ? month - 1
                : (month + 10) % 12];
    }

    /**
     * @return 指定月份的天数
     */
    public int getDaysOfMonth(int year, int month)
    {
        int days = 0;
        if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8
                || month == 10 || month == 12)
        {
            days = 31;
        } else
        {
            if (month == 2)
            {
                if ((year % 400 == 0) || ((year % 4 == 0) && (year % 100 != 0)))
                {
                    days = 29;
                } else
                {
                    days = 28;
                }
            } else
            {
                days = 30;
            }
        }
        return days;
    }
}
